home *** CD-ROM | disk | FTP | other *** search
/ Future Workshop / Future Workshop.iso / multimed / qtw111 / pviewer / zoomctrl.c < prev   
C/C++ Source or Header  |  1994-01-11  |  29KB  |  760 lines

  1.  
  2. // ---------------------------------------------------------------------
  3. //
  4. // ZoomCtrl.c - Picture Viewer - QuickTime for Windows
  5. //
  6. //              Version 1.0
  7. //
  8. //              (c) 1988-1992 Apple Computer, Inc. All Rights Reserved.
  9. //
  10. // ---------------------------------------------------------------------
  11.  
  12.  
  13. // Includes
  14. // --------
  15. #define NOMINMAX
  16. #include <Windows.H> // Required by Windows
  17. #include <stdlib.h>  // Required for abs function
  18.  
  19. #include <qtole.h>  // Interface to qtole dll
  20. #include <qtw.h>    // Interface to QuickTime
  21.                     // Needed for struct defs in picture.h
  22. #include "common.h" // Interface to common.c
  23.  
  24. #include "viewer.h"  // Interface to *.c files
  25. #include "viewer.hr" // Defines used in *.rc files
  26. #include "picture.h" // Interface to picture window
  27.                      // child window processing
  28.  
  29. // Consts
  30. // ---------
  31. // These are used instead of GetSysColors because user may change 
  32. // system colors using control panel in which case, our colors would
  33. // no longer match the Windows button colors which do not change
  34. #define BTNFACECOLOR        (RGB( 192, 192, 192 ))
  35. #define BTNSHADOWCOLOR      (RGB( 128, 128, 128 ))
  36. #define BTNHIGHLIGHTCOLOR   (RGB( 255, 255, 255 ))
  37.  
  38. #define TEXT_HEIGHT           7 // Text height in points 
  39. #define TEXT_EXTRA_SPACING    2 // Extra spacing between characters in
  40.                                 // percent text
  41.  
  42.  
  43. // This struct defines the bounds of the zones used by the zoom control
  44. typedef struct // Hungarian notation: zns
  45.   {POINT      ptBuckle;         // position of UL corner of buckle
  46.                                 // in the corresponding zone
  47.     WORD       wZoomMultiplier; // Zoom scaling multiplier
  48.     char       szPercent[8];    // percent text i.e. "150%   "
  49.                                 // This string is padded with with blanks
  50. } ZONES, * NPZONES;
  51.  
  52. // Message-Persistent Data
  53. // -----------------------
  54. static struct // Hungarian notation: g
  55.   {                                     // These bitmaps and dimensions are used in the zoom control
  56.                                         // They are shared by all instances
  57.     RECT        rcBar;                  // Rect defining belt in control
  58.     RECT        rcYard;                 // Rect defining area in which mouse
  59.                                         // dragging works. When the mouse is
  60.                                         // dragged outside this rect, the
  61.                                         // buckle does not follow
  62.     HBITMAP     hbmpActiveBuckle;       // Handle to active buckle bitmap
  63.     WORD        wBuckleWidth;           // Width of buckle bitmap
  64.     WORD        wBuckleHeight;          // Height of buckle bitmap
  65.     ZONES       znsZones[NUM_OF_ZOOMS]; // Array of zone structs
  66.     POINT       ptText;                 // Upper-Left corner of % text
  67.     int         nTextHeight;            // % Text height
  68.     WORD        wWidthWnd;              // Adjusted window width after  
  69.                                         // correcting for font size
  70.   } g;
  71.  
  72.  
  73.  
  74. // Internal Function Declarations
  75. // ------------------------------
  76. static LONG NEAR BuildBuckleStuff     (HWND);
  77. static LONG NEAR UpdateBuckleAndText  (HWND, HDC, NPPICTUREDATA, WORD,
  78.                                                    HBITMAP, BOOL, BOOL);
  79. static VOID NEAR Draw3DRect           (HDC, int, int, int, int);
  80. static LONG NEAR DrawBuckle           (HDC, NPPICTUREDATA, NPZONES,
  81.                                                     HBITMAP, BOOL, BOOL);
  82. static WORD NEAR PointToZoomIndex     (PPOINT, WORD);
  83.  
  84.  
  85. // Function: PictureZoomWndProc - Window proc for the picture resizing
  86. //                                scroll bar
  87. // --------------------------------------------------------------------
  88. // Parameters: As required by Microsoft Windows
  89. //
  90. // Returns:    Via DefWindowProc
  91. // --------------------------------------------------------------------
  92. LONG __export CALLBACK PictureZoomWndProc
  93.     (HWND hwndZoom, UINT message, WPARAM wParam, LPARAM lParam)
  94.  
  95. {                               // These statics are only used during mouse capture
  96.     static BOOL     bDragging;  // Dragging flag
  97.     static WORD     wZoomIndex; // Current zoom index during dragging
  98.  
  99.     NPPICTUREDATA   pPictureData;  // -> picture data struct
  100.     PAINTSTRUCT     ps;            // Paint struct
  101.     HDC             hdc;           // Control dc
  102.     RECT            rcZoom;        // Client rect of control
  103.     HWND            hwndPicture;   // Handle of picture window
  104.     HBRUSH          hbrush;        // Handle of brush
  105.     HBRUSH          hbrushSave;    // Handle of prev brush
  106.     NPZONES         pznsZone;      // -> zone struct
  107.     POINT           ptMouse;       // Mouse position
  108.     WORD            wNewZoomIndex; // New zoom index
  109.     RECT            rcBuckle;      // Buckle rect
  110.  
  111.  
  112.     if( !(pPictureData = (NPPICTUREDATA)
  113.         GetWindowWord( hwndPicture = GetParent( hwndZoom ), 0 )))
  114.         return DefWindowProc( hwndZoom, message, wParam, lParam);
  115.  
  116.     switch( message ) {
  117.         case WM_CREATE:
  118.             // Set statics: rcBar, zones and bitmaps for buckle
  119.             // This data is shared by all instances
  120.             if( !g.hbmpActiveBuckle && BuildBuckleStuff( hwndZoom ))
  121.                 return -1L;
  122.  
  123.             // Create a bitmap that will save the area under the buckle
  124.             // Each instance gets one of these
  125.             if( !( hdc = GetDC( hwndZoom ))) {
  126.                 CommonTellUser( ViewerQueryResources(),
  127.                     VIEWER_STRING_NODC, VIEWER_STRING_CAPTION, MB_OK );
  128.                 return 0L;
  129.             }
  130.  
  131.             if( !(pPictureData->zsZoomScroll.hbmpNotBuckle =
  132.                 CreateCompatibleBitmap( hdc,
  133.                 g.wBuckleWidth, g.wBuckleHeight ))) {
  134.                 CommonTellUser( ViewerQueryResources(),
  135.                     VIEWER_STRING_NOMEMORY, NULL, MB_OK );
  136.  
  137.                 ReleaseDC( hwndZoom, hdc );
  138.                 return -1L;
  139.             }
  140.  
  141.             ReleaseDC( hwndZoom, hdc );
  142.             return 0L;
  143.  
  144.         case WM_KEYDOWN:
  145.             switch( wParam ) {
  146.                 case VK_ADD:
  147.                 case VK_SUBTRACT:
  148.                     wZoomIndex =
  149.                         pPictureData->zsZoomScroll.wCurZoomIndex +
  150.                         ((wParam == VK_ADD) ? 1 : -1);
  151.                     if( (wZoomIndex < IMAGE_SIZE_FIRST ) ||
  152.                         (wZoomIndex >= IMAGE_SIZE_FIRST + NUM_OF_ZOOMS))
  153.                         return 0L;
  154.  
  155.                     if( !(hdc = GetDC( hwndZoom ))) {
  156.                         CommonTellUser( ViewerQueryResources(),
  157.                             VIEWER_STRING_NODC,
  158.                             VIEWER_STRING_CAPTION, MB_OK );
  159.                         return 0L;
  160.                     }
  161.  
  162.                     UpdateBuckleAndText( hwndZoom, hdc, pPictureData,
  163.                         wZoomIndex, g.hbmpActiveBuckle, FALSE, TRUE );
  164.                     ReleaseDC( hwndZoom, hdc );
  165.  
  166.                     ZoomPicture( hwndPicture, wZoomIndex );
  167.  
  168.                     return 0L;
  169.  
  170.                 default:
  171.                     break;
  172.             }
  173.             break;
  174.  
  175.         case WM_LBUTTONDOWN:
  176.             ptMouse = MAKEPOINT( lParam );
  177.             if( !PtInRect( &g.rcBar, ptMouse ))
  178.                 return 0L;
  179.  
  180.             wZoomIndex = PointToZoomIndex( &ptMouse,
  181.                 pPictureData->zsZoomScroll.wCurZoomIndex );
  182.  
  183.             if( wZoomIndex != pPictureData->zsZoomScroll.wCurZoomIndex ) {
  184.                 if( !(hdc = GetDC( hwndZoom ))) {
  185.                     CommonTellUser( ViewerQueryResources(),
  186.                         VIEWER_STRING_NODC,
  187.                         VIEWER_STRING_CAPTION, MB_OK );
  188.                     return 0L;
  189.                 }
  190.  
  191.                 UpdateBuckleAndText( hwndZoom, hdc, pPictureData,
  192.                     wZoomIndex, g.hbmpActiveBuckle, FALSE, TRUE );
  193.                 ReleaseDC( hwndZoom, hdc );
  194.             }
  195.  
  196.             SetCapture( hwndZoom );
  197.             bDragging = TRUE;
  198.  
  199.             return 0L;
  200.  
  201.         case WM_LBUTTONUP:
  202.             if( bDragging ) {
  203.                 ReleaseCapture();
  204.                 ZoomPicture( hwndPicture, wZoomIndex );
  205.             }
  206.             bDragging = FALSE;
  207.             return 0L;
  208.  
  209.         case WM_MOUSEMOVE:
  210.             if( !bDragging )
  211.                 return 0L;
  212.  
  213.             ptMouse = MAKEPOINT( lParam );
  214.             if( PtInRect( &g.rcYard, ptMouse )) {
  215.                 if( wZoomIndex == ( wNewZoomIndex = 
  216.                     PointToZoomIndex( &ptMouse, wZoomIndex )))
  217.                     return 0L;
  218.             }
  219.             else {
  220.                 wNewZoomIndex = pPictureData->zsZoomScroll.wCurZoomIndex;
  221.             }
  222.  
  223.             wZoomIndex = wNewZoomIndex;
  224.  
  225.             if( !(hdc = GetDC( hwndZoom ))) {
  226.                 CommonTellUser( ViewerQueryResources(),
  227.                     VIEWER_STRING_NODC, VIEWER_STRING_CAPTION, MB_OK );
  228.                 return 0L;
  229.             }
  230.  
  231.             UpdateBuckleAndText( hwndZoom, hdc, pPictureData, wZoomIndex,
  232.                 g.hbmpActiveBuckle, FALSE, TRUE );
  233.             ReleaseDC( hwndZoom, hdc );
  234.  
  235.             return 0L;
  236.  
  237.         // WM_USER messages
  238.  
  239.         case WM_ZOOM_MOVEBUCKLE:
  240.             if( !(hdc = GetDC( hwndZoom ))) {
  241.                 CommonTellUser( ViewerQueryResources(),
  242.                     VIEWER_STRING_NODC, VIEWER_STRING_CAPTION, MB_OK );
  243.                 return 0L;
  244.             }
  245.  
  246.             UpdateBuckleAndText( hwndZoom, hdc, pPictureData,
  247.                 pPictureData->zsZoomScroll.wCurZoomIndex,
  248.                 g.hbmpActiveBuckle, FALSE, TRUE );
  249.             ReleaseDC( hwndZoom, hdc );
  250.             return 0L;
  251.  
  252.         // End WM_USER messages
  253.  
  254.         case WM_PAINT:
  255.             pznsZone = g.znsZones +
  256.                 pPictureData->zsZoomScroll.wCurZoomIndex -
  257.                 IMAGE_SIZE_FIRST;
  258.  
  259.             // Force repaint of the buckle to prevent the
  260.             // repainting logic from getting off
  261.             *((LPPOINT) &rcBuckle.left) = 
  262.                 pPictureData->zsZoomScroll.ptBucklePos;
  263.             rcBuckle.right  = rcBuckle.left + g.wBuckleWidth;
  264.             rcBuckle.bottom = rcBuckle.top  + g.wBuckleHeight;
  265.             InvalidateRect( hwndZoom, &rcBuckle, TRUE );
  266.  
  267.             if( !BeginPaint( hwndZoom, &ps ))
  268.                 return 0L;
  269.  
  270.             GetClientRect( hwndZoom, &rcZoom );
  271.  
  272.             // Draw the main rect
  273.             if( !( hbrush = CreateSolidBrush( BTNFACECOLOR ))) {
  274.                 EndPaint( hwndZoom, &ps );
  275.                 return 0L;
  276.             }
  277.             FillRect( ps.hdc, &rcZoom, hbrush );
  278.             DeleteObject( hbrush );
  279.  
  280.             // Draw the belt
  281.             if( !( hbrush = CreateSolidBrush( BTNSHADOWCOLOR ))) {
  282.                 EndPaint( hwndZoom, &ps );
  283.                 return 0L;
  284.             }
  285.             hbrushSave = SelectObject( ps.hdc, hbrush );
  286.             Rectangle( ps.hdc, g.rcBar.left, g.rcBar.top,
  287.                 g.rcBar.right, g.rcBar.bottom );
  288.             DeleteObject( SelectObject( ps.hdc, hbrushSave ));
  289.  
  290.             // Draw the buckle
  291.             UpdateBuckleAndText( hwndZoom, ps.hdc, pPictureData,
  292.                 pPictureData->zsZoomScroll.wCurZoomIndex,
  293.                 g.hbmpActiveBuckle, TRUE, TRUE );
  294.  
  295.             EndPaint( hwndZoom, &ps );
  296.  
  297.             return 0L;
  298.  
  299.         case WM_DESTROY:
  300.             // Each instance has one of these
  301.             if( pPictureData->zsZoomScroll.hbmpNotBuckle ) {
  302.                 DeleteObject( pPictureData->zsZoomScroll.hbmpNotBuckle );
  303.                 pPictureData->zsZoomScroll.hbmpNotBuckle = NULL;
  304.             }
  305.  
  306.             // All instances share these
  307.             if( ViewerQueryNumPictures() <= 1 ) {
  308.                 if( g.hbmpActiveBuckle )
  309.                     DeleteObject( g.hbmpActiveBuckle );
  310.                 g.hbmpActiveBuckle   = NULL;
  311.             }
  312.  
  313.             pPictureData->zsZoomScroll.hwnd = NULL;
  314.  
  315.             return 0L;
  316.  
  317.         default:
  318.             break;
  319.     }
  320.  
  321.     return DefWindowProc( hwndZoom, message, wParam, lParam);
  322.  
  323. }
  324.  
  325.  
  326. // Function: UpdateBuckleAndText - Draws the buckle and text
  327. // --------------------------------------------------------------------
  328. // Parameters: HWND           hwndZoom          Window handle of control
  329. //             HDC            hdc               DC of control
  330. //             NPPICTUREDATA  pPictureData      -> picture data struct
  331. //             WORD           wZoomIndex        Current zoom index
  332. //             HBITMAP        hbmpBuckle        Handle of buckle bitmap
  333. //             BOOL           bRepainting       Repainting flag
  334. //             BOOL           bUpdateNoBuckle   Update no buckle bitmap flag
  335. //
  336. // Returns:    LONG             0L if OK
  337. // --------------------------------------------------------------------
  338. static LONG NEAR UpdateBuckleAndText( HWND hwndZoom,
  339.                    HDC hdc, NPPICTUREDATA pPictureData,
  340.                          WORD wZoomIndex, HBITMAP hbmpBuckle,
  341.                                 BOOL bRepainting, BOOL bUpdateNoBuckle )
  342.  
  343. {
  344.     NPZONES    pznsZone;   // -> zone struct
  345.     HFONT      hFont;      // Handle to font used for % text
  346.     HFONT      hsaveFont;  // Prev font
  347.     COLORREF   dwcrSave;   // Prev color
  348.     UINT       uSaveAlign; // Prev text alignment
  349.  
  350.  
  351.     pznsZone = g.znsZones + wZoomIndex - IMAGE_SIZE_FIRST;
  352.  
  353.     // Draw the buckle in the new position
  354.     if( DrawBuckle(hdc, pPictureData, pznsZone, hbmpBuckle,
  355.         bRepainting, bUpdateNoBuckle ))
  356.         return 0L;
  357.  
  358.     // Get the font. Don't bother with error message. If this
  359.     // fails, the system font will be used
  360.     if( hFont = MakeAnArialFont( hdc, g.nTextHeight ))
  361.         hsaveFont = SelectObject( hdc, hFont );
  362.  
  363.     SetTextCharacterExtra( hdc, 
  364.         GetTextCharacterExtra( hdc ) + TEXT_EXTRA_SPACING );
  365.  
  366.     dwcrSave = SetBkColor( hdc, BTNFACECOLOR );
  367.  
  368.     // Draw the % text
  369.     uSaveAlign = SetTextAlign( hdc, TA_LEFT | TA_BASELINE );
  370.     TextOut( hdc, g.ptText.x, g.ptText.y, pznsZone->szPercent,
  371.         lstrlen( pznsZone->szPercent ));
  372.     SetTextAlign( hdc, uSaveAlign );
  373.  
  374.     if( hFont )
  375.         DeleteObject( SelectObject( hdc, hsaveFont ));
  376.     SetBkColor( hdc, dwcrSave );
  377.  
  378.     return 0L;
  379. }
  380.  
  381.  
  382. // Function: DrawBuckle - Draws the buckle
  383. // --------------------------------------------------------------------
  384. // Parameters: HDC              hdc              hdc of control
  385. //             NPPICTUREDATA    pPictureData     -> to picturedata struct
  386. //             NPZONES          pznsZone         -> zone struct. Contains
  387. //                                               offsets used to position buckle
  388. //             HBITMAP          hbmpBuckle       Buckle bitmap
  389. //             BOOL             bRepainting      TRUE if WM_PAINT message
  390. //             BOOL             bUpdateNoBuckle  TRUE if area under buckle
  391. //                                               should be saved. This is
  392. //                                               false if only changing
  393. //                                               activation state of buckle
  394. //
  395. // Returns:    LONG             0L if OK
  396. // --------------------------------------------------------------------
  397. static LONG NEAR DrawBuckle( HDC hdc, NPPICTUREDATA pPictureData,
  398.                          NPZONES pznsZone, HBITMAP hbmpBuckle,
  399.                                  BOOL bRepainting, BOOL bUpdateNoBuckle )
  400.  
  401. {
  402.     HDC           hdcMem;   // Memory device context
  403.     HBITMAP       hbmpSave; // Prev bitmap
  404.  
  405.  
  406.     if( !(hdcMem = CreateCompatibleDC( hdc ))) {
  407.         CommonTellUser( ViewerQueryResources(),
  408.             VIEWER_STRING_NODC, VIEWER_STRING_CAPTION, MB_OK );
  409.         return VIEWER_STRING_NODC;
  410.     }
  411.  
  412.     hbmpSave = SelectObject( hdcMem,
  413.         pPictureData->zsZoomScroll.hbmpNotBuckle );
  414.     // Use no buckle bitmap to remove buckle
  415.     if( !bRepainting ) {
  416.         BitBlt( hdc, pPictureData->zsZoomScroll.ptBucklePos.x,
  417.             pPictureData->zsZoomScroll.ptBucklePos.y,
  418.             g.wBuckleWidth, g.wBuckleHeight,
  419.             hdcMem, 0, 0, SRCCOPY );
  420.     }
  421.  
  422.     // Save area under new position of buckle
  423.     if( bUpdateNoBuckle ) {
  424.         BitBlt( hdcMem, 0, 0, g.wBuckleWidth, g.wBuckleHeight,
  425.             hdc, pznsZone->ptBuckle.x, pznsZone->ptBuckle.y, SRCCOPY );
  426.         pPictureData->zsZoomScroll.ptBucklePos = pznsZone->ptBuckle;
  427.     }
  428.  
  429.     // Draw buckle
  430.     SelectObject( hdcMem, hbmpBuckle );
  431.     BitBlt( hdc, pznsZone->ptBuckle.x, pznsZone->ptBuckle.y,
  432.         g.wBuckleWidth, g.wBuckleHeight, hdcMem, 0, 0, SRCCOPY );
  433.  
  434.     SelectObject( hdcMem, hbmpSave );
  435.     DeleteDC( hdcMem );
  436.  
  437.     return 0L;
  438. }
  439.  
  440.  
  441. // Function: BuildBuckleStuff - processes WM_CREATE message for
  442. //                              zoom wnd control
  443. // --------------------------------------------------------------------
  444. // Parameters: HWND         hwndZoom       Window handle of zoom control
  445. //
  446. // Returns:    LONG         0L if OK
  447. // --------------------------------------------------------------------
  448. static LONG NEAR BuildBuckleStuff( HWND hwndZoom )
  449.  
  450. {
  451.     RECT     rcClient;         // Client rect of window
  452.     POINT    ptBuckle;         // Temp UL corner of buckle
  453.     WORD     wBar;             // Length of bar
  454.     WORD     wBar1;            // Temp length of bar
  455.     WORD     wBar2;            // Temp length of bar
  456.     WORD     wBuckleP1;        // Width of buckle + 1 pixel
  457.     HDC      hdc;              // Device context of control
  458.     HDC      hdcMem;           // Memory dc
  459.     HBITMAP  hbmpSave;         // Prev bitmap
  460.     char     szFormat[6];      // Resource string format for % text
  461.     int      i;                // Temp index
  462.     int      j;                // Temp index
  463.     WORD     wBarHeight;       // Bar height
  464.     WORD     wBuckleExtension; // Half the amount by which buckle height exceeds
  465.                                // bar height
  466.     WORD     wMaxTextExtent;   // Max text extent of % text
  467.     WORD     wTextExtent;      // Text extent of % text
  468.     HFONT    hFont;            // Font used to display % text
  469.     HFONT    hsaveFont;        // Prev font
  470.     TEXTMETRIC tm;             // Text metrics struct
  471.     BOOL     bGotTextMetrics;  // TRUE if GetTextMetrics worked 
  472.     WORD     wAveChar;         // Average width of % text char
  473.     int      nMaxTextHeight;   // Max text height
  474.  
  475.  
  476.     static WORD wZoomMults[NUM_OF_ZOOMS] = // Array of zoom multipliers
  477.           { 25, 50, 75, 100, 150, 200, 400 }; // that define the scaling
  478.  
  479.  
  480.     GetClientRect( hwndZoom, &rcClient );
  481.  
  482.     // rcYard defines the area within which the control responds to
  483.     // mouse dragging
  484.     g.rcYard = rcClient;
  485.     g.rcYard.left   -= (WORD) GetSystemMetrics( SM_CXVSCROLL );
  486.     g.rcYard.right  += (WORD) GetSystemMetrics( SM_CXVSCROLL );
  487.     g.rcYard.top    -= (WORD) GetSystemMetrics( SM_CYHSCROLL );
  488.     g.rcYard.bottom += (WORD) GetSystemMetrics( SM_CYHSCROLL );
  489.  
  490.     // Set rect for slider bar
  491.     g.rcBar.left   = rcClient.bottom / 3;
  492.     g.rcBar.right  = g.rcBar.left + (65 * rcClient.right / 100 );
  493.     g.rcBar.top    = max( 3 * rcClient.bottom / 10, 3 );
  494.     g.rcBar.bottom = rcClient.bottom - g.rcBar.top;
  495.     wBar = g.rcBar.right - g.rcBar.left;
  496.     wBarHeight = g.rcBar.bottom - g.rcBar.top;
  497.  
  498.     wBuckleExtension = ( rcClient.bottom - wBarHeight - 2 ) / 2;
  499.     if( wBuckleExtension > 2 )
  500.         wBuckleExtension = 2;
  501.     g.wBuckleHeight = wBarHeight + 2 * wBuckleExtension;
  502.  
  503.     // Set buckle width and then adjust bar or buckle length so that
  504.     // bar length is integral number of buckles long + 2 pixels
  505.  
  506.     g.wBuckleWidth = ( wBar - NUM_OF_ZOOMS - 1 ) / NUM_OF_ZOOMS;
  507.     wBar1 = ( g.wBuckleWidth + 1 ) * NUM_OF_ZOOMS + 1;
  508.     wBar2 = ( (g.wBuckleWidth + 1) + 1 ) * NUM_OF_ZOOMS + 1;
  509.     if( abs( wBar - wBar1 ) >= abs( wBar - wBar2 )) {
  510.         g.wBuckleWidth += 1;
  511.         g.rcBar.right = g.rcBar.left + wBar2;
  512.     }
  513.     else {
  514.         g.rcBar.right = g.rcBar.left + wBar1;
  515.     }
  516.  
  517.  
  518.     if( !(hdc = GetDC( hwndZoom ))) {
  519.         CommonTellUser( ViewerQueryResources(),
  520.             VIEWER_STRING_NODC, VIEWER_STRING_CAPTION, MB_OK );
  521.         return VIEWER_STRING_NODC;
  522.     }
  523.  
  524.     // Set zones
  525.     // Initialize text strings
  526.     LoadString( ViewerQueryResources(), VIEWER_STRING_PERCENT,
  527.         szFormat, sizeof( szFormat ));
  528.     wMaxTextExtent = 0;
  529.     // Set text height
  530.     g.nTextHeight = -MulDiv( TEXT_HEIGHT,
  531.         GetDeviceCaps( hdc, LOGPIXELSY ), 72 );
  532.     // Limit text height to 2/3 of the window height
  533.     nMaxTextHeight = -MulDiv( 2, rcClient.bottom, 3 );
  534.     // use max because values are < 0
  535.     g.nTextHeight = max( g.nTextHeight, nMaxTextHeight );
  536.  
  537.     // Select font into dc so GetTextExtent will work
  538.     if( hFont = MakeAnArialFont( hdc, g.nTextHeight ))
  539.         hsaveFont = SelectObject( hdc, hFont );
  540.  
  541.     SetTextCharacterExtra( hdc, 
  542.         GetTextCharacterExtra( hdc ) + TEXT_EXTRA_SPACING );
  543.  
  544.     for( i=0; i < NUM_OF_ZOOMS; i++ ) { // Save multipliers for Query function
  545.         g.znsZones[i].wZoomMultiplier = wZoomMults[i]; 
  546.         wsprintf( g.znsZones[i].szPercent, szFormat,
  547.             g.znsZones[i].wZoomMultiplier );
  548.                                         // Get text extent before padding with blanks
  549.         wTextExtent = LOWORD( GetTextExtent( hdc, g.znsZones[i].szPercent, 
  550.             lstrlen( g.znsZones[i].szPercent )));
  551.         if( wMaxTextExtent < wTextExtent ) {
  552.             wMaxTextExtent = wTextExtent;
  553.             wAveChar = wMaxTextExtent / lstrlen( g.znsZones[i].szPercent );
  554.         }
  555.  
  556.         // Now pad with blanks to erase previous text
  557.         for(j=lstrlen( g.znsZones[i].szPercent );
  558.             j < sizeof( g.znsZones[i].szPercent ) - 1; j++ )
  559.             g.znsZones[i].szPercent[j] = ' ';
  560.         g.znsZones[i].szPercent[j] = '\0';
  561.     }
  562.  
  563.     bGotTextMetrics = GetTextMetrics( hdc, &tm );
  564.  
  565.     if( hFont )
  566.         DeleteObject( SelectObject( hdc, hsaveFont ));
  567.  
  568.     // Initialize buckle positions and zone edges
  569.     wBuckleP1  = g.wBuckleWidth + 1;
  570.     ptBuckle.x = g.rcBar.left + 1;
  571.     ptBuckle.y = g.rcBar.top - wBuckleExtension;
  572.     for( i=0; i < NUM_OF_ZOOMS; i++ ) {
  573.         g.znsZones[i].ptBuckle = ptBuckle;
  574.         ptBuckle.x += wBuckleP1;
  575.     }
  576.  
  577.     if( !(hdcMem = CreateCompatibleDC( hdc ))) {
  578.         ReleaseDC( hwndZoom, hdc );
  579.         CommonTellUser( ViewerQueryResources(),
  580.             VIEWER_STRING_NODC, VIEWER_STRING_CAPTION, MB_OK );
  581.         return VIEWER_STRING_NODC;
  582.     }
  583.  
  584.     // build buckle
  585.     if( !( g.hbmpActiveBuckle = CreateCompatibleBitmap
  586.         ( hdc, g.wBuckleWidth, g.wBuckleHeight ))) {
  587.         DeleteDC( hdcMem );
  588.         ReleaseDC( hwndZoom, hdc );
  589.         CommonTellUser( ViewerQueryResources(),
  590.             VIEWER_STRING_NOMEMORY, NULL, MB_OK );
  591.         return VIEWER_STRING_NOMEMORY;
  592.     }
  593.  
  594.     hbmpSave = SelectObject( hdcMem, g.hbmpActiveBuckle );
  595.  
  596.     Draw3DRect( hdcMem, 0, 0, g.wBuckleWidth, g.wBuckleHeight );
  597.  
  598.     SelectObject( hdcMem,  hbmpSave );
  599.     DeleteDC( hdcMem );
  600.  
  601.     // Set reference point for TextOut
  602.     g.ptText.x = g.rcBar.right + 4;
  603.     if( bGotTextMetrics ) {
  604.         g.ptText.y = max( g.rcBar.bottom, 
  605.             ( rcClient.bottom +
  606.             tm.tmAscent - tm.tmInternalLeading ) / 2 );
  607.     }
  608.     else {
  609.         g.ptText.y = g.rcBar.bottom;
  610.     }
  611.  
  612.     // Now make sure text will fit in window, adjust width if it doesn't
  613.     g.wWidthWnd = g.ptText.x + wMaxTextExtent + ( 3 * wAveChar / 2 );
  614.  
  615.     ReleaseDC( hwndZoom, hdc );
  616.  
  617.     return 0L;
  618. }
  619.  
  620. // Function: Draw3DRect - Draws the 3D stuff on a given rect
  621. // --------------------------------------------------------------------
  622. // Parameters: HDC              hdc          Device context
  623. //             int              left         Rect.left
  624. //             int              top          Rect.top
  625. //             int              right        Rect.right
  626. //             int              bottom       Rect.bottom
  627. //
  628. // Returns:    VOID
  629. // --------------------------------------------------------------------
  630. static VOID NEAR Draw3DRect( HDC hdc,
  631.                         int nleft, int ntop, int nright, int nbottom )
  632.  
  633. {
  634.     HPEN     hpenSave;     // Prev pen
  635.     HPEN     hpenHighLite; // HighLite pen
  636.     HPEN     hpenShadow;   // Shadow pen
  637.     HBRUSH   hbrush;       // Brush
  638.     HBRUSH   hbrushSave;   // Prev brush
  639.  
  640.  
  641.     // Don't bother with error messages. Failure here will not cause a
  642.     // crash. The rects just won't look right.
  643.  
  644.     if( hbrush = CreateSolidBrush( BTNFACECOLOR )) {
  645.         hbrushSave = SelectObject( hdc, hbrush );
  646.         Rectangle( hdc, nleft, ntop, nright, nbottom );
  647.         DeleteObject( SelectObject( hdc, hbrushSave ));
  648.     }
  649.  
  650.     if( hpenShadow = CreatePen( PS_SOLID, 1, BTNSHADOWCOLOR)) {
  651.         hpenSave = SelectObject( hdc, hpenShadow );
  652.         MoveTo( hdc, nright - 2, 1 );
  653.         LineTo( hdc, nright - 2, nbottom - 2 );
  654.         LineTo( hdc, 0, nbottom - 2);
  655.         DeleteObject( SelectObject( hdc, hpenSave ));
  656.     }
  657.  
  658.     if( hpenHighLite = CreatePen( PS_SOLID, 1, BTNHIGHLIGHTCOLOR )) {
  659.         hpenSave = SelectObject( hdc, hpenHighLite );
  660.         MoveTo( hdc, 1, nbottom - 3 );
  661.         LineTo( hdc, 1, 1 );
  662.         LineTo( hdc, nright - 2, 1 );
  663.         DeleteObject( SelectObject( hdc, hpenSave ));
  664.     }
  665.  
  666.     return;
  667. }
  668.  
  669.  
  670. // Function: PointToZoomIndex - Finds index of zoon cooresponding to mouse
  671. //                              position
  672. // --------------------------------------------------------------------
  673. // Parameters: PPOINT       pptMouse         -> current mouse position
  674. //             WORD         wCurZoneIndex    Current zone index
  675. //
  676. // Returns:    WORD         wZoomIndex
  677. // --------------------------------------------------------------------
  678. static WORD NEAR PointToZoomIndex( PPOINT pptMouse, WORD wCurZoneIndex )
  679.  
  680. {
  681.     int        nxPos;    // Horizontal position of mouse
  682.     WORD       iCur;     // Current zone -> offset
  683.     WORD       i;        // Counter
  684.     int        nWidthP1; // Width of buckle + 1 pixel
  685.  
  686.     nxPos = pptMouse->x;
  687.     nWidthP1 = g.wBuckleWidth + 1;
  688.     iCur = wCurZoneIndex - IMAGE_SIZE_FIRST;
  689.  
  690.     // Check if left of first zone
  691.     if( nxPos <= g.znsZones[0].ptBuckle.x + nWidthP1)
  692.         return IMAGE_SIZE_FIRST;
  693.  
  694.     // Check if in current zone
  695.     if( ( nxPos >= g.znsZones[iCur].ptBuckle.x - 1 ) &&
  696.         ( nxPos <= g.znsZones[iCur].ptBuckle.x + nWidthP1 ))
  697.         return wCurZoneIndex;
  698.  
  699.     // Check rest of zones
  700.     for(i=0; i < NUM_OF_ZOOMS; i++ ) {
  701.         if(( i != iCur ) &&
  702.             ( nxPos <= g.znsZones[i].ptBuckle.x + nWidthP1 ))
  703.             return ( i + IMAGE_SIZE_FIRST );
  704.     }
  705.  
  706.     return ( IMAGE_SIZE_FIRST + NUM_OF_ZOOMS - 1 );
  707. }
  708.  
  709.  
  710. //  The remaining functions are the query functions called by other modules
  711.  
  712. // Function: ViewerQueryZoomMultiplier - Query the zoom multiplier for the
  713. //                                       current zoom index
  714. // --------------------------------------------------------------------
  715. // Parameters: WORD           wZoomIndex    Current zoom index
  716. //
  717. // Returns:    WORD           wZoomMult     Corresponding zoom muliplier
  718. // --------------------------------------------------------------------
  719. WORD FAR ViewerQueryZoomMultiplier( WORD wZoomIndex )
  720.  
  721. {
  722.     return g.znsZones[wZoomIndex - IMAGE_SIZE_FIRST].wZoomMultiplier;
  723. }
  724.  
  725.  
  726. // Function: ViewerQueryZoomIndex - Query the zoom index for the
  727. //                                  current zoom multiplier 
  728. // --------------------------------------------------------------------
  729. // Parameters: WORD           wZoomMult     Current zoom muliplier
  730. //
  731. // Returns:    WORD           wZoomIndex    Corresponding zoom index
  732. // --------------------------------------------------------------------
  733. WORD FAR ViewerQueryZoomIndex( WORD wZoomMultiplier )
  734.  
  735. {
  736.     int      i;
  737.  
  738.     for( i=0; i < NUM_OF_ZOOMS - 1; i++ ) {
  739.         if( wZoomMultiplier <= g.znsZones[i].wZoomMultiplier )
  740.             break;
  741.     }
  742.  
  743.     return ( i + IMAGE_SIZE_FIRST );
  744. }
  745.  
  746.  
  747. // Function: ViewerQueryZoomWndWidth - Query the final width of the 
  748. //                                     zoom window after adjustment for
  749. //                                     font (see BuildBuckleStuff())
  750. // --------------------------------------------------------------------
  751. // Parameters: VOID
  752. //
  753. // Returns:    WORD    wWidthWnd     final width of control
  754. // --------------------------------------------------------------------
  755. WORD FAR ViewerQueryZoomWndWidth( VOID )
  756.  
  757. {
  758.     return g.wWidthWnd;
  759. }
  760.